<?php
/**
 * @version 1.0
 * @package lib
 * @subpackage data
 * @name CMySQLStore
 * @deprecated connect and query with MySQL
 * @todo CMySQLStore is extend CStore
*/

class CMySQLStore extends CStore{
	/**
	 * @var string handle của mysql
	 */
	public $id = false;
	/**
	 * @var string Host của database
	 */
	public $host;
	/**
	 * @var string username của database
	 */
	public $username;
	/**
	 * @var string password của database
	 */
	public $password;
	/**
	 * @var string tên của database
	 */
	public $database;

	public $slave_id = false;
	/**
	 * @var string Host của database
	 */
	public $slave_host;
	/**
	 * @var string username của database
	 */
	public $slave_username;
	/**
	 * @var string password của database
	 */
	public $slave_password;
	public $slave_database;
	public $slave_connected = false;


	/**
	 * Khởi tạo đối tượng CMySQLStore
	 *
	 * @param Địa chỉ $host
	 * @param Username của DB $username
	 * @param mật khẩu của DB $password
	 * @param tên của DB $database
	 */
	function __construct($host, $username, $password, $database, $slave_host = false, $slave_username = false, $slave_password = false, $slave_database = false)
	{
		$this->host = $host;
		$this->username = $username;
		$this->password = $password;
		$this->database = $database;
		$this->slave_host = $slave_host?$slave_host:$host;
		$this->slave_username = $slave_username?$slave_username:$username;
		$this->slave_password = ($slave_password!==false)?$slave_password:$password;
		$this->slave_database = $slave_database?$slave_database:$database;
	}
	/**
	 * Phương thức tạo kết nối đến DB
	 *
	 */
	function connect($utf8 = 0)
	{

		if(!$this->connected or $utf8 == 1)
		{
			
			if($this->id = mysql_connect($this->host, $this->username, $this->password))
			{
				mysql_select_db($this->database);
//				if($utf8 == 1) {
//					mysql_query("SET NAMES 'utf8'", $this->id);
//				}
				mysql_query("SET NAMES 'utf8'", $this->id);
				$this->connected = true;
				if($this->slave_host == $this->host and $this->slave_database == $this->database)
				{
					$this->slave_id = $this->id;
					$this->slave_connected = true;
				}
			}
			else
			{
				$this->connected = true;
				//Thong bao qua tai
				//echo '<script>location="http://static.vict.vn/";</ script>';
				//CSystem::end();
			}
		}
	}
	function slave_connect($utf8 = 0)
	{

		if($this->slave_host != $this->host or $this->slave_database != $this->database)
		{
			if(!$this->slave_connected  or $utf8 == 1)
			{
				$connect_func = 'mysql_'.(portal()->setting('mysql-slave-persistent-connection')?'p':'').'connect';
				if($this->slave_id = $connect_func($this->slave_host, $this->slave_username, $this->slave_password))
				{
					mysql_select_db($this->database);
//					if ($utf8 == 1) {
//						mysql_query("SET NAMES 'utf8'", $this->id);
//					}
					mysql_query("SET NAMES 'utf8'", $this->slave_id);
					$this->slave_connected = true;
				}
				else
				{
					//Thong bao qua tai
					echo '<script>location="http://error.vict.vn/";</script>';
					CSystem::end();
				}
			}
		}
		else
		{
			$this->connect();
		}
	}
	/**
	 * Phương thức đóng DB
	 *
	 */
	function close()
	{
		if($this->connected)
		{
			mysql_close($this->id);
			$this->connected = false;
		}
		if(!portal()->setting('mysql-slave-persistent-connection'))
		{
			if(($this->slave_host != $this->host  or $this->slave_database != $this->database) and $this->slave_connected)
			{
				mysql_close($this->slave_id);
			}
			$this->slave_connected = false;
		}
	}
	/**
	 * Phương thức lấy ra bản ghi đầu tiên của bảng table trong CSDL
	 *
	 * @param Tên bảng $table
	 * @param Điểu kiện lựa chọn các bản ghi $condition kiểu array
	 * @param Các tùy chọn lựa chọn các bản ghi trong bảng $options kiểu mảng
	 * @return Nội dung bản ghi đầu tiên trong bảng table
	 */
	function select($table, $conditions = false, $options = array())
	{
		$condition_string = $this->condition_string($conditions);
		if (isset($options['cache'])) {
		  $cache_name = 'data'.$table.md5($condition_string.@$options['items_per_page']);
		  if (!isset($options['clearcache'])) {
			  $ret = CSystem::$cachedata->get($cache_name);
			  if (null!=$ret) return $ret;
		  }
		}
		$slave = isset($options['slave'])?$options['slave']:true;
		$typeReturn = isset($options['typeReturn'])?true:false;

		if($slave)
		{
			$this->slave_connect();
		}
		else
		{
			$this->connect();
		}
		$options = array_merge(array(
			'fields'=>'*',
			'group_by' => '',
			'joins' => array(),
			'order_by' => false,
			'order_type'=>'',
			'page_no' => 1,
			'items_per_page' => 1000
		),$options);
		if(is_array($options['fields']))
		{
			$fields_string = '`'.join('`,`',$options['fields']).'`';
		}
		else
		{
			$fields_string = $options['fields'];
		}
		$joins = $this->joins_string($table, $options['joins']);

		$query ='
SELECT
	'.$fields_string.'
FROM
	`'.$table.'`
'.$joins.'
'.($condition_string?'
WHERE
	'.$this->condition_string($conditions):'').'
'.($options['group_by']?' GROUP BY '.$options['group_by']:'').'
'.($options['order_by']?' ORDER BY '.$options['order_by'].' '.$options['order_type']:'');
	if(!isset($options['status_limit']) or (isset($options['status_limit']) and $options['status_limit'] == true)){
		$query .= ' LIMIT '.(($options['page_no']-1)*$options['items_per_page']).','.$options['items_per_page'].' ';
	}
		$item = $this->fetch($query, $slave, $typeReturn);
		if (isset($cache_name)) {
		  CSystem::$cachedata->set($cache_name, $item, $options['cache']);
		}
		return $item;
	}
	function joins_string($table, $joins)
	{
		$st = '';
		if($joins)
		{
			foreach($joins as $join)
			{
				$st .= '
'.((isset($join['type']) and $join['type'])?$join['type']:'INNER').' JOIN `'.$join['table'].'` ON ';
				if(is_string($join['condition']))
				{
					$st .= '`'.$join['table'].'`.id = `'.$table.'`.'.$join['condition'];
				}
				else
				{
					$st .= $this->condition_string($join['condition']);
				}
			}
		}
		return $st;
	}
	/**
	 * Phương thức đếm số bản ghi thỏa mãn ĐK
	 *
	 * @param Tên bảng $table kiểu chuỗi
	 * @param Các điều kiện $conditions kiểu mảng
	 * @return Số bản ghi thỏa mãn điều kiện conditions
	 */
	function count($table, $conditions=false, $options=array()) {
		$slave = isset($options['slave'])?$options['slave']:true;

		if($slave) {
			$this->slave_connect();
		} else {
			$this->connect();
		}
		$condition_string = $this->condition_string($conditions);
		if(isset($options['joins'])) {
			$joins = $this->joins_string($table, $options['joins']);
		} else {
			$joins = '';
		}

		$sql = '
SELECT
	count(*) as total
FROM
	`'.$table.'`
'.$joins.'
'.($condition_string?'
WHERE
	'.$this->condition_string($conditions):'').'
'.((isset($options['group_by']) and $options['group_by'])?' GROUP BY '.$options['group_by']:'');

		// Check for cache option
		if (isset($options['cache'])) {
		  $cache_name = 'count'.$table.md5($sql);
		  if (!@$options['clear_cache'] && $ret = CSystem::$cachedata->get($cache_name)) {
		  	return $ret;
		  } else {
		  	$row = $this->fetch($sql, $slave);
		  	$row = $row['total'];
		  	CSystem::$cachedata->set($cache_name, $row);
		  	return $row;
		  }
		} else {
			$row = $this->fetch($sql, $slave);
			return $row['total'];
		}
	}


	/**
	 * Thực hiện một truy vấn đến DB
	 *
	 * @param Nội dung truy vấn $query_string thuộc kiểu chuỗi
	 * @return Kết quả của truy vấn
	 */
	function query($query_string, $slave = false)
	{
		if(DEBUG and (request('query'))){
			if(!isset($this->iCount)){
				$this->iCount = 0;
			}
			echo '<div style="clear:both; padding-top:10px; top:50px; clear:both;"><div style="color:blue;">'.$query_string.'</div>';
			echo '<div style="color:red;font-weight:bold; clear:both;">'.++$this->iCount.'</div></div>';
		}

		if(DEBUG)
		{
			CLog()->log('QUERY',$query_string);
		}
		try
		{
			//echo $i = isset($i)?++$i:0 .'<br />';
			if($slave?$this->slave_id:$this->id)
			{
				if (defined('SLOW_QUERY_LOG')) {
					$time = microtime(true);
					if(DEBUG and (request('profile'))){
						$start = $this->getTime();
					}
					$result = mysql_query($query_string,$slave?$this->slave_id:$this->id);
					if(DEBUG and (request('profile'))){
						$this->createLog($query_string,$start);
					}
					if (($time=microtime(true)-$time)>1) {
						error_log("\n\n\n$query_string", 3, ROOT_DIR.'publish/slowquery.txt');
					}
				} else {
					if(DEBUG and (request('profile'))){
						$start = $this->getTime();
					}
					$result = mysql_query($query_string,$slave?$this->slave_id:$this->id);
					if(DEBUG and (request('profile'))){
						$this->createLog($query_string,$start);
					}
				}
			}
			else
			{
				return false;
			}
		}
		catch(Exception $e)
		{
			return false;
		}
		return $result;
	}

	function fetch($query_string = false, $slave = false, $typeReturn = false)
	{
		try
		{
			if ($slave) {
				$this->slave_connect();
			} else {
				$this->connect();
			}
			if(!$query_string) {
			  if (isset($this->result)) {
  				if ($typeReturn){
  					return mysql_fetch_object($this->result);
  				} else {
  					return mysql_fetch_assoc($this->result);
  				}
			  }
			} else if($this->result = $this->query($query_string, $slave)) {
				//????
				if (defined('SLOW_QUERY_LOG')) {
					$name = module()->name;
					error_log(date('m:d H:i:s').' '.$name.': '.$query_string."\r\n\r\n\r\n", 3, ROOT_DIR.'publish/query.txt');
				}
				//var_dump($query_string);
				if ($typeReturn) {
					return mysql_fetch_object($this->result);
				} else {
					return mysql_fetch_assoc($this->result);
				}
			}
		} catch(Exception $e) {
		}
	}
	/**
	 * Phương thức chèn bản ghi có giá trị values vào trong bảng
	 *
	 * @param tên bảng $table kiểu chuỗi
	 * @param Các giá trị của bản ghi  $values kiểu array
	 * @return Bảng sau khi đã chèn bản ghi
	 */
	function insert($table, $values)
	{
		$this->connect();
		$query='insert into';
		$query.=' `'.$table.'`(';
		$i=0;
		if(is_array($values))
		{
			foreach($values as $key=>$value)
			{
				if(($key===0) or is_numeric($key))
				{
					$key=$value;
				}
				if($key)
				{
					if($i<>0)
					{
						$query.=',';
					}
					$query.='`'.$key.'`';
					$i++;
				}
			}
			$query.=') values(';
			$i=0;
			foreach($values as $key=>$value)
			{
				if(is_numeric($key) or $key===0)
				{
					$value=Url::get($value);
				}
				if($i<>0)
				{
					$query.=',';
				}

				if($value==='NULL')
				{
					$query.='NULL';
				}
				else
				{
					$query.='\''.(is_array($value)?'':mysql_real_escape_string($value)).'\'';
				}
				$i++;
			}

			$query.=')';
      if (defined('SLOW_QUERY_LOG')) {
				$name = module()->name;
				error_log(date('H:i:s').' '.$name."\n".$query."\n\n\n", 3, ROOT_DIR.'publish/insert.txt');
			}
			if($this->query($query)) {
				return mysql_insert_id($this->id);
			}
		}
	}
	/**
	 * Phương thức cập nhật các giá trị mới cho các bản ghi thỏa mãn điều kiện conditions
	 *
	 * @param tên bảng $table kiểu chuỗi
	 * @param Các giá trị mới cần cập nhật $values kiểu array
	 * @param điều kiện của các bản ghi được cập nhật $conditions
	 * @return Trả về giá trị True nếu các bản ghi được cập  nhật thành công.
	 */
	function update($table, $values, $conditions)
	{
		$this->connect();
		$query='update `'.$table.'` set ';
		$i=0;
		if($values)
		{
			foreach($values as $key=>$value)
			{

				if($key===0 or is_numeric($key))
				{
					$key=$value;
					$value=request($value);
				}
				if($i<>0)
				{
					$query.=',';
				}
				if($key)
				{
					if($value==='NULL')
					{
						$query.='`'.$key.'`=NULL';
					}
					// Khoanb Edit 08.05.2009
					else
					if(is_array($value) and $value['operation'] and $value['value'])
					{
						$query.='`'.$key.'`='.$key.$value['operation'].$value['value'];
					}
					else
					if(is_object($value))
					{
						$query.='`'.$key.'`='.$this->condition_string($value);
					}
					else
					{
						$query.='`'.$key.'`=\''.mysql_real_escape_string($value).'\'';
					}
					$i++;
				}
			}
			if($condition_string = $this->condition_string($conditions))
			{
				$query.=' where '.$condition_string;
			}
			if (defined('SLOW_QUERY_LOG')) {
				$name = module()->name;
      	error_log(date('H:i:s').' '.$name."\n".$query."\n\n\n", 3, ROOT_DIR.'publish/update.txt');
      }
			return $this->query($query);
		}
	}
	/**
	 * Phương thức xóa các bản ghi thỏa mãn điều kiện conditions
	 *
	 * @param tên bảng $table kiểu
	 * @param unknown_type $conditions
	 */
	function delete($table, $conditions)
	{
		$this->connect();
		$this->query('DELETE FROM `'.$table.'` WHERE '.$this->condition_string($conditions));
	}
	static function convert_conditions($operator, $factors)
	{
		switch ($operator) {
			case 'EXPRESSION':
				return $factors[0];
			case 'COLUMN':
				if(is_array($factors[0]))
				{
					print_r($factors[0]);
					echo '<pre>';
					debug_print_backtrace();
					exit();
				}
				return preg_match('/[^a-zA-Z0-9_]/',$factors[0])?' '.$factors[0].' ':' `'.addslashes($factors[0]).'` ';
				break;
			case 'FULLTEXT':
				return 'MATCH ('.$factors[0].') AGAINST ('.$factors[1].' IN BOOLEAN MODE)';
				break;
			case 'LIKE':
				return '('.$factors[0].' LIKE "%'.substr($factors[1],2,strlen($factors[1])-4).'%")';
				break;
			case 'NLIKE':
				return '('.$factors[0].' NOT LIKE "%'.substr($factors[1],2,strlen($factors[1])-4).'%")';
				break;
			case 'BW':
				return '('.$factors[0].' LIKE "'.substr($factors[1],2,strlen($factors[1])-4).'%")';
				break;
			case 'EW':
				return '('.$factors[0].' LIKE "%'.substr($factors[1],2,strlen($factors[1])-4).'")';
				break;
			case 'INT':
				$factors[0] = intval($factors[0]);
				return ' "'.mysql_escape_string($factors[0]).'" ';
				break;
			case 'REAL':
				$factors[0] = floatval($factors[0]);
				return ' "'.mysql_escape_string($factors[0]).'" ';
				break;
			case 'STRING':
				return ' "'.mysql_escape_string($factors[0]).'" ';
				break;
			case 'ID':
				return '(`id` = '.$factors[0].')';
				break;
			case '!':
				return ' NOT '.$factors[0].' ';
				break;
			case '!=':
				return '('.$factors[0].' <> '.$factors[1].')';
				break;
			case 'NOT_NULL':
				return '('.$factors[0].' is not null)';
				break;
			case 'NULL':
				return '('.$factors[0].' is null)';
				break;
			case 'IN':
				$sub_factors = array();
				for($i = 1; $i< sizeof($factors); $i++)
				{
					$sub_factors[] = '( '.$factors[0].' = '.$factors[$i].' )';
				}
				return '( '.join(' OR ', $sub_factors).' )';
				break;
			default:
				return '( '.join(' '.$operator.' ', $factors).' )';
				break;
		}
	}
	function condition_string($conditions)
	{
		if(is_string($conditions) or is_numeric($conditions))
		{
			$conditions = EId($conditions);
		}
		else
		{
			$conditions = CExpression::pre_process_conditions($conditions);
		}
		if($conditions)
		{
			return $conditions->parse('CMySQLStore::convert_conditions');
		}
		return false;
	}

	/**
	 * Select all rows
	 *
	 * @param unknown_type $table
	 * @param unknown_type $conditions
	 * @param unknown_type $options
	 * @return unknown
	 */
	function select_all($table, $conditions = false, $options = array())
	{
		$items = array();
		if(!isset($options['items_per_page'])) {
			$options['items_per_page'] = 1000;
		}

		$cache_time = @$options['cache'];
		if (isset($cache_time)) {
			$condition_string = $this->condition_string($conditions);
		  $cache_name = 'data'.$table.md5($condition_string.@$options['items_per_page']);
		  if (!isset($options['clearcache'])) {
			  $ret = CSystem::$cachedata->get($cache_name);
			  if (null!=$ret) return $ret;
		  }
		  unset($options['cache']);
		}

		if($item = $this->select($table, $conditions, $options)) {
			do {
				if (isset($item['id'])) {
					$items[$item['id']] = $item;
				} else {
					$items[] = $item;
				}
			} while($item = $this->fetch());
		}

		if (isset($cache_name)) {
			CSystem::$cachedata->set($cache_name, $items, $cache_time);
		}
		return $items;
	}

	/*-----------------------------------
	          	PROFILE QUERY
	------------------------------------*/
	function createLog($query_string = '', $start = ''){
		if(!isset($GLOBALS['queries']['queryCount'])){
			$GLOBALS['queries']['queryCount'] = 0;
		}
		++$GLOBALS['queries']['queryCount'];
		$this->logQuery($query_string, $start);
	}

	/*-----------------------------------
	          	DEBUGGING
	------------------------------------*/

	function logQuery($sql, $start) {
		if(!isset($GLOBALS['queries']['query'])){
			$GLOBALS['queries']['query'] = array();
		}
		$query = array(
				'sql' => $sql,
				'time' => ($this->getTime() - $start)*1000
			);		
		array_push($GLOBALS['queries']['query'], $query);
	}

	function getTime() {
		$time = microtime();
		$time = explode(' ', $time);
		$time = $time[1] + $time[0];
		$start = $time;
		return $start;
	}

	public function getReadableTime($time) {
		$ret = $time;
		$formatter = 0;
		$formats = array('ms', 's', 'm');
		if($time >= 1000 && $time < 60000) {
			$formatter = 1;
			$ret = ($time / 1000);
		}
		if($time >= 60000) {
			$formatter = 2;
			$ret = ($time / 1000) / 60;
		}
		$ret = number_format($ret,3,'.','') . ' ' . $formats[$formatter];
		return $ret;
	}
}
?>
